home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Bug Proofing Visual Basic: A Guide to Error Handling and Prevention
(Publisher: John Wiley & Sons, Inc.)
Author(s): Rod Stephens
ISBN: 0471323519
Publication Date: 11/01/98

Search this book:
 
Previous Table of Contents Next


CHAPTER 8
Gotchas

This chapter describes several of the most common bugs in Visual Basic programs and ways to avoid them. Most are quite simple once you learn about them. Many are difficult to foresee, however, and they can be very time consuming if you are forced to learn about them by direct experience.

A lot of Visual Basic programmers including myself have wasted a lot of time learning about these gotchas the hard way. After you read this chapter, you should be able to easily avoid the most costly of these mistakes.

Watch Precision in Tests

Checking equality of integers is easy. Two integers are either equal or they are not. Sometimes the equality of floating-point numbers can be a little more confusing. Two floating-point numbers can be very close to the same value and still not be equal.

In the following code, the variable x starts with the value 0. The value 10 / 17 is added to x 17 times. If you multiply 17 by 10 / 17, you get 10, so the final value for x should be 10. Due to round-off errors, however, the value is actually 9.999999. This is not exactly 10, so the test x = 10 in the If statement is false and the message box is not displayed.

Private Sub RoundoffProblem()
Dim x As Single
Dim dx As Single
Dim i As Integer

    dx = 10 / 17
    x = 0
    For i = 1 To 17
        ‘ Do something with x.
           :
         x = x + dx
    Next i

    If x = 10 Then MsgBox “This value is 10.”
End Sub

This can be even more confusing with double precision floating-point numbers. The following code is similar to the previous routine except it uses double precision numbers. Once again, the test in the If statement is false, so the program does not display the message box.

Private Sub RoundoffProblem()
Dim x As Double
Dim dx As Double
Dim i As Integer

    dx = 10 / 17
    x = 0
    For i = 1 To 17
        ‘ Do something with x.
            :
         x = x + dx
    Next i

    If x = 10 Then MsgBox “This value is 10.”
End Sub

After the For loop in this routine, x is actually 9.999999999999998. This is not exactly 10, so the program does not display the message box.

To make matters worse, the value of x is so close to 10 that the Format function displays it as 10. The Debug.Print statement and the debugger’s quick watch also display x as 10. If you use the format statement, the Debug.Print statement, or Visual Basic’s quick watch feature, you will see that x is 10, but the If statement will still not display the message box. This can be extremely confusing. The variable x seems to be 10, but the test x = 10 is false.

To avoid this sort of confusion, never use equality to decide whether two floating-point numbers have the same value. Instead, check whether they are within a certain small distance of each other. For example, the following code fragment shows how to determine whether x is 10 to within 0.00001. This is close enough to equality for most purposes.

If Abs(x - 10) < 0.00001 Then MsgBox “This value is approximately 10.”

Similarly, never use a simple inequality test (<>) to decide whether two floating-point numbers are different. The following loop runs forever because x is never exactly equal to 10.

Private Sub RoundoffProblem()
Dim x As Single
Dim dx As Single

    dx = 10 / 17
    x = 0
    Do While x <> 10
        ‘ Do something with x.
            :
         x = x + dx
    Loop
End Sub

Control Float Loops with While

The previous guideline says you should not test floating-point numbers for equality. If you use a floating-point variable to control a For loop, you are implicitly doing just that. Each time the loop runs, Visual Basic checks to see if the variable has reached the loop’s stopping value. This step tests for equality, so it can cause some subtle errors.

The For loop in the following code should execute four times with x equal to 0, 10 / 3, 20 / 3, and 10. It actually executes with x equal to 0, 3.33333333333333, and 6.66666666666667. When the program adds 10 / 3 to x the third time, x becomes roughly 10.0000000000000003. That is greater than 10 so the For loop exits before executing a fourth time. Instead of executing four times, this code runs only three times.

Private Sub RoundoffProblem()
Dim x As Double

    For x = 0 To 10 Step 10 / 3
        ‘ Do something with x.
            :
        Next x
End Sub

To avoid this kind of problem, eliminate the equality test implicit in the For loop. Use a While loop instead and replace the equality test with the proper inequality. In this case, the code should continue to execute the loop until x is greater than 10 plus a small amount to account for rounding errors.

Private Sub RoundoffProblem()
Dim x As Double

    x = 0
    Do
        ‘ Do something with x.
            :

        x = x + 10 / 3
    Loop While x < 10.00001
End Sub

This code executes the For loop statements four times as desired.

Control Float Loops with Integers

If you know how many times you want a loop to execute, use an integer instead of a floating-point number to control the loop. The following code accomplishes the same task as the code from the previous section without the confusing inequality or rounding problems.

Private Sub RoundoffProblem()
Dim x As Double
Dim i As Integer

    x = 0
    For i = 0 To 3
        ‘ Do something with x.
             :

        x = x + 10 / 3
    Next i
End Sub

This code executes the For loop statements four times as desired without using the confusing While statement. Despite the fact that this code uses an extra integer variable, the two versions run in almost exactly the same amount of time.

Control Date Loops

Date and time variables are stored internally as floating-point numbers so they are subject to the same rounding errors as other floating-point numbers. The following code should execute a For loop four times with the variable the_time set to 1:00, 1:20, 1:40, and 2:00. Due to rounding, after dx is added to x three times, x has the value 2:00:00.00000000000000001. This is bigger than 2:00, so the loop stops after executing only three times instead of four.

Private Sub RoundoffProblem()
Dim the_time As Date
Dim dx As Date

    ‘ Use 1/3 hour increments.
    dx = 1 / 24 / 3

    For the_time = CDate(“1:00 am”) To CDate(“2:00 am”) Step dx
        ‘ Do something with the_time.
             :
    Next the_time
End Sub

This problem has the same solutions as other floating-point looping problems. Use While loops with inequalities instead of For loops controlled by floating-point numbers. If you know how many times you want the loop to execute, use an integer variable to control the loop instead.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.